import pandas as pd
from openpyxl.styles import Font, Alignment, PatternFill
from openpyxl.utils import get_column_letter
from concurrent.futures import ProcessPoolExecutor
from utils.alicloud.cms import AliCloudCmsClient
from utils.alicloud.ecs import AliCloudEcsClient
from utils.msg_notice import WechatNotifier
from utils.config_loader import load_config
from utils.logger import setup_logger

# -------------基础配置---------------
config = load_config()
notifier = WechatNotifier(
    webhook_url=config["wechat"]["webhook_url"],
    upload_url=config["wechat"]["upload_url"])
success_logger = setup_logger("success", config["log"]["success_log"], level="INFO")
error_logger = setup_logger("error", config["log"]["error_log"], level="ERROR")


def generate_report(df: pd.DataFrame, output_file: str = None):
    """
    生成Excel格式的巡检报告
    :param df: 包含巡检数据的DataFrame
    :param output_file: 输出文件名
    """
    try:
        # 如果没有提供输出文件路径，使用默认路径
        if output_file is None:
            report_dir = config["report"]["path"]
            output_file = f"{report_dir}/ecs_inspection_report.xlsx"
            
        success_logger.info(f'正在生成Excel报告 {output_file}...')
        with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
            df.to_excel(writer, sheet_name='ECS巡检报告', index=False)
            worksheet = writer.sheets['ECS巡检报告']
            # 设置列宽
            for col in worksheet.columns:
                max_len = max((len(str(cell.value)) if cell.value else 0) for cell in col)
                col_letter = get_column_letter(col[0].column)
                worksheet.column_dimensions[col_letter].width = (max_len + 2) * 1.2

            # 设置表头样式
            header_style = {
                'fill': PatternFill(start_color='4472C4', fill_type='solid'),
                'font': Font(color='FFFFFF', bold=True),
                'alignment': Alignment(horizontal='center', vertical='center')
            }
            for cell in worksheet[1]:
                for attr, value in header_style.items():
                    setattr(cell, attr, value)

            # 设置数据对齐 + 条件格式高亮
            for row in worksheet.iter_rows(min_row=2):
                for cell in row:
                    if cell.column > 5:
                        # 尝试数值处理
                        try:
                            value = float(cell.value)
                            cell.alignment = Alignment(horizontal='right')

                            if value > 80:
                                cell.fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid')
                                cell.font = Font(color='FFFFFF')
                            elif 80 >= value >= 75:
                                cell.fill = PatternFill(start_color='FFC000', end_color='FFC000', fill_type='solid')
                        except (ValueError, TypeError):
                            # 非数字或空值跳过
                            continue

        success_logger.info("巡检报告生成完成")

    except Exception as e:
        error_logger.error(f'生成Excel报告时出错：{e}')


def get_metrics(client, metric_func):
    """通用方法获取监控指标"""
    try:
        return metric_func() or {}
    except Exception as e:
        error_logger.error(f'获取监控指标失败: {e}')
        return {}


def collect_region_data(region_id):
    """
    收集单个区域的数据
    :params: region_id
    :return: 包含巡检数据的DataFrame
    """
    success_logger.info(f'正在收集{region_id}的ECS实例信息....')
    region_data = []
    try:
        # 创建ecs cms客户端
        ecs_client = AliCloudEcsClient(region_id)
        cms_client = AliCloudCmsClient(region_id)
        # 获取实例信息
        instances = ecs_client.get_instances()
        if not instances:
            error_logger.warning(f'{region_id}没有实例或获取失败...')
        # 获取监控数据
        metrics = {
            'cpu': get_metrics(cms_client, cms_client.get_cpu_metrics),
            'memory': get_metrics(cms_client, cms_client.get_memory_metrics),
            'disk': get_metrics(cms_client, cms_client.get_disk_metrics)
        }
        # 将实例的监控数据与实例信息进行合并
        for inst in instances:
            inst_id = inst['instance_id']
            data = {
                'Region': region_id,
                '实例ID': inst_id,
                '实例名称': inst['instance_name'],
                'IP地址': inst['ip_address'],
                '状态': inst['status'],
                '操作系统类型': inst['os_type'],
                '操作系统名称': inst['os_name'],
                'CPU使用率': metrics['cpu'].get(inst_id, 'N/A'),
                '内存使用率': metrics['memory'].get(inst_id, 'N/A')
            }
            # 添加磁盘数据
            data.update(metrics['disk'].get(inst_id, {}))
            region_data.append(data)
    except Exception as e:
        error_logger.error(f'{region_id}的数据收集失败：{e}')
    return region_data


class EcsInspection:
    def __init__(self):
        self.region_ids = config["aliyun"]["region_id"]

    def collect_inspection_data(self):
        """
        收集ecs巡检数据
        :return: 包含巡检数据的DataFrame
        """
        success_logger.info('开始收集ECS巡检数据....')
        all_data = []

        # 使用线程池并行处理
        with ProcessPoolExecutor(max_workers=min(len(self.region_ids), 5)) as executor:
            results = list(executor.map(collect_region_data, self.region_ids))
        # 合并结果
        for region_data in results:
            all_data.extend(region_data)
        return pd.DataFrame(all_data) if all_data else pd.DataFrame()

